﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;

using ProfileManager.Comparers;
using ProfileManager.Helpers;
using ProfileManager.Properties;
using SortOrder = System.Windows.Forms.SortOrder;


namespace ProfileManager.DataAccess
{
    public class UserInfo
    {
        public Guid Id { get; set; }
        public string Login { get; set; }
        public string Email { get; set; }
        public string Password { get; set; }
        public DateTime DateCreated { get; set; }
        public bool Deleted { get; set; }

        public enum SortingFields
        {
            Login,
            Email,
            DateCreated
        }

        public void Insert()
        {
            try
            {
                if (!IsExist())
                {
                    using (SqlConnection con = CommonDb.GetBaseConection())
                    {
                        Guid newId = Guid.NewGuid();

                        SqlCommand saveCmd = new SqlCommand("UserInfoInsert", con);
                        saveCmd.CommandType = CommandType.StoredProcedure;

                        saveCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = newId;
                        saveCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(Login);
                        saveCmd.Parameters.Add("@Email", SqlDbType.VarBinary).Value = Crypto.Encrypt(Email);
                        saveCmd.Parameters.Add("@Password", SqlDbType.VarBinary).Value = Crypto.Encrypt(Crypto.GetMd5Sum(Password));

                        con.Open();
                        
                        bool isRowsAffected = saveCmd.ExecuteNonQuery() > 0;
                        if (isRowsAffected)
                        {
                            Id = newId;
                        }
                    }
                }
                else
                {
                    ShowMessage.Error(Resources.SelectedLoginIsExist);
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
            }
        }

        public bool Update()
        {
            try
            {
                if (!IsExist())
                {
                    Password = !Password.Equals(Select(Id).Password) ? Crypto.GetMd5Sum(Password) : Password;

                    using (SqlConnection con = CommonDb.GetBaseConection())
                    {
                        SqlCommand updCmd = new SqlCommand("UserInfoUpdate", con);
                        updCmd.CommandType = CommandType.StoredProcedure;

                        updCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = Id;
                        updCmd.Parameters.Add("@Email", SqlDbType.VarBinary).Value = Crypto.Encrypt(Email);
                        updCmd.Parameters.Add("@Password", SqlDbType.VarBinary).Value = Crypto.Encrypt(Password);

                        con.Open();
                        return updCmd.ExecuteNonQuery() > 0;
                    }
                }
                return false;
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return false;
            }
        }

        public static bool Delete(Guid id)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetBaseConection())
                {
                    SqlCommand delCmd = new SqlCommand("UserInfoDelete", con);
                    delCmd.CommandType = CommandType.StoredProcedure;

                    delCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = id;

                    con.Open();
                    return delCmd.ExecuteNonQuery() > 0;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return false;
            }
        }

        public static UserInfo Select(Guid id)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetBaseConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoSelectById", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = id;

                    con.Open();
                    List<UserInfo> cList = MapFrom(getCmd.ExecuteReader());

                    return cList != null ? cList.FirstOrDefault() : null;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }

        public static List<UserInfo> Select()
        {
            try
            {
                using (SqlConnection con = CommonDb.GetBaseConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoSelectAll", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    con.Open();
                    return MapFrom(getCmd.ExecuteReader());
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }

        public static Guid UserLogin(string userLogin, string userPassword)
        {
            try
            {
                using (SqlConnection con = CommonDb.GetBaseConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoLogin", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(userLogin);
                    getCmd.Parameters.Add("@Password", SqlDbType.VarBinary).Value = Crypto.Encrypt(Crypto.GetMd5Sum(userPassword));

                    con.Open();

                    SqlDataReader getReader = getCmd.ExecuteReader();
                    return getReader.HasRows && getReader.Read() ? Guid.Parse(getReader["Id"].ToString()) : Guid.Empty;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return Guid.Empty;
            }
        }

        private bool IsExist()
        {
            try
            {
                using (SqlConnection con = CommonDb.GetBaseConection())
                {
                    SqlCommand getCmd = new SqlCommand("UserInfoIsExist", con);
                    getCmd.CommandType = CommandType.StoredProcedure;

                    getCmd.Parameters.Add("@Id", SqlDbType.UniqueIdentifier).Value = Id != Guid.Empty ? (object)Id : DBNull.Value;
                    getCmd.Parameters.Add("@Login", SqlDbType.VarBinary).Value = Crypto.Encrypt(Login);

                    con.Open();
                    return Convert.ToInt32(getCmd.ExecuteScalar()) > 0;
                }
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return true;
            }
        }

        private static List<UserInfo> MapFrom(SqlDataReader dr)
        {
            try
            {
                if (dr != null && dr.HasRows)
                {
                    List<UserInfo> acList = new List<UserInfo>();
                    while (dr.Read())
                    {
                        UserInfo wt = new UserInfo
                            {
                                Id = Guid.Parse(dr["Id"].ToString()),
                                Login = Crypto.Decrypt((byte[])dr["Login"]),
                                Email = Crypto.Decrypt((byte[])dr["Email"]),
                                Password = Crypto.Decrypt((byte[])dr["Password"]),
                                DateCreated = Convert.ToDateTime(dr["DateCreated"]),
                                Deleted = Convert.ToBoolean(dr["Deleted"]),
                            };

                        acList.Add(wt);
                    }
                    acList.Sort(new UserInfoComparer(SortingFields.Login, SortOrder.Ascending));
                    return acList;
                }
                return null;
            }
            catch (Exception ex)
            {
                Logger.WriteLog(ex);
                return null;
            }
        }

        public override string ToString()
        {
            return Login;
        }
    }
}